Skip to content

Fix list_projects empty + trace_path qualified-name lookup#298

Closed
nv-jwiley wants to merge 1 commit intoDeusData:mainfrom
nv-jwiley:fix/list-projects-and-trace-path-qualified-name
Closed

Fix list_projects empty + trace_path qualified-name lookup#298
nv-jwiley wants to merge 1 commit intoDeusData:mainfrom
nv-jwiley:fix/list-projects-and-trace-path-qualified-name

Conversation

@nv-jwiley
Copy link
Copy Markdown
Contributor

Summary

Two bugs in src/mcp/mcp.c surfaced during a real-world MCP tool sweep against a mode=full index of a 12,770-node Python repo on macOS arm64. Both have minimal, targeted fixes.

Bug 1 — list_projects returns {"projects":[]} even when projects exist

Symptom: After index_repository(...) succeeds, the project is fully queryable via index_status, search_code, search_graph, query_graph, get_code_snippet, trace_path, etc., but list_projects returns an empty array.

Root cause: is_project_db_file() (mcp.c:846, also inlined inside collect_db_project_names at mcp.c:791) excludes any filename with a tmp- prefix. But cbm_project_name_from_path() legitimately produces tmp-... project names for source roots under /tmp/ — verified by an existing in-tree test:

// tests/test_pipeline.c:1903
{"/tmp/bench/erlang/lib/stdlib/src", "tmp-bench-erlang-lib-stdlib-src"},

Any project rooted under /tmp was silently filtered from list_projects + the available_projects hint inside build_project_list_error.

Fix: drop the tmp- prefix exclusion entirely. SQLite's actual journal/WAL sidecar files end with -journal, -wal, -shm (not .db) and never collide with the .db suffix is_project_db_file already requires, so removing the prefix filter is safe. While here, refactor collect_db_project_names() to call is_project_db_file() so the filter lives in one place.

Bug 2 — trace_path returns function not found for fully-qualified names

Symptom: Calling trace_path with a fully-qualified function name ("<project>.module.submodule.func") returns {"error":"function not found", ...} even when the node exists. The tool's own error hint instructs callers to "fully qualify" the name, but doing so causes the lookup to miss every time — the documented "fully qualify for precise match" UX inverts what actually works.

Root cause: handle_trace_call_path() (mcp.c:1887) only calls cbm_store_find_nodes_by_name(), which queries WHERE project = ?1 AND name = ?2 against the bare name column. The qualified name is never tried.

Fix: when the bare-name lookup returns 0 nodes, fall back to cbm_store_find_node_by_qn() (already exists in store.c, used elsewhere). If that resolves, wrap the single result into the same nodes[] array the downstream BFS expects, so the rest of the function is unchanged.

Verification

Built locally with make -f Makefile.cbm cbm, replaced the cached binary at ~/Library/Caches/codebase-memory-mcp/0.6.0/codebase-memory-mcp on macOS arm64, restarted the host service, and verified against a real Users-jwiley-dev-orca index (12,770 nodes / 36,859 edges) plus a synthetic tmp-cbm_sandbox project rooted at /tmp/cbm_sandbox:

  • Pre-patch: list_projects returned {"projects":[]}.
    Post-patch: returns both tmp-cbm_sandbox and Users-jwiley-dev-orca.

  • Pre-patch: trace_path(function_name="Users-jwiley-dev-orca.src.services.session_enricher.enrichment_service.run_enrichment") returned function not found.
    Post-patch: returns identical callees (29 nodes across hops 1+2) and callers (2 nodes) to the bare-name lookup trace_path(function_name="run_enrichment").

Existing tests untouched.

Test plan

  • Verified patched binary builds cleanly with -O2 -Wall -Wextra -Werror on macOS arm64
  • Verified list_projects now surfaces a tmp-cbm_sandbox project (was previously filtered)
  • Verified trace_path with bare name (control) still works
  • Verified trace_path with fully-qualified name returns identical traversal
  • CI on this PR (Linux + Windows builds + make -f Makefile.cbm test)

Two related bugs surfaced during a real-world tool sweep against an
orca install (DGX Spark agent platform).  Both patches are in
src/mcp/mcp.c, the in-process MCP request handler.

1) list_projects returned an empty array even when projects were
   indexed and queryable.

   Root cause: is_project_db_file() (mcp.c:846, also duplicated inline
   in collect_db_project_names at mcp.c:791) excluded any filename with
   a "tmp-" prefix.  But cbm_project_name_from_path() legitimately
   produces "tmp-..." project names for source roots under /tmp/
   (covered by tests/test_pipeline.c:1903 — "/tmp/bench/erlang/lib/
   stdlib/src" → "tmp-bench-erlang-lib-stdlib-src").  Any project rooted
   under /tmp got silently filtered from list_projects + the
   "available_projects" hint inside build_project_list_error.

   Fix: drop the "tmp-" prefix exclusion entirely.  SQLite's actual
   journal/WAL files end with `-journal`, `-wal`, `-shm` (not `.db`)
   and never collide with the `.db` suffix the function already
   requires, so removing the prefix filter is safe.  While here,
   refactor collect_db_project_names() to call is_project_db_file()
   so the filter logic lives in one place.

2) trace_path returned "function not found" when called with a
   fully-qualified function name like
   "Users-foo-dev-myrepo.src.module.func".

   Root cause: handle_trace_call_path() (mcp.c:1887) only called
   cbm_store_find_nodes_by_name(), which queries `WHERE name = ?2`
   (the bare name column).  The tool's own error hint tells callers
   to "fully qualify" the name, but doing so caused the lookup to
   miss every time.

   Fix: when the bare-name lookup returns 0 nodes, fall back to
   cbm_store_find_node_by_qn() (already exists in store.c).  If that
   resolves, wrap the single result into the same nodes[] array the
   downstream BFS expects, so the rest of the function is unchanged.

Verified locally on macOS arm64 against a real 12,770-node /36,859-edge
mode=full index — list_projects now lists all projects (including
tmp-rooted ones), and trace_path with a fully-qualified name returns
identical callees/callers to the bare-name lookup.
@DeusData DeusData added the bug Something isn't working label May 4, 2026
@DeusData
Copy link
Copy Markdown
Owner

Thanks @nv-jwiley — both diagnoses are spot on, both root causes are correctly identified, and the fixture you cited (tests/test_pipeline.c proving cbm_project_name_from_path("/tmp/...") legitimately produces "tmp-...") is the conclusive piece of evidence. I verified both bugs still reproduce against current main exactly as you described.

Landed on main as two atomic commits with you as co-author:

  • eb0627e fix(mcp): list_projects no longer hides tmp-prefixed projects — drops the tmp- prefix exclusion in is_project_db_file, plus the cleanup you suggested routing collect_db_project_names through that helper so the filter lives in one place.
  • 9818730 fix(mcp): trace_path falls back to qualified_name lookup — adds the cbm_store_find_node_by_qn fallback. One small addition over your patch: a NULL check on malloc(sizeof(cbm_node_t)) with free_node_contents(&qn_node) on the failure path so the qn_node strdups don't leak on OOM. The forward decl pattern you used for is_project_db_file made that easy — same pattern for free_node_contents.

Why two commits instead of merging the PR directly: the branch base is from April 16, and main has since landed extensive pagination documentation in the tool descriptions and a safe_str_free refactor in cbm_jsonrpc_request_free. Merging the PR as-is would have reverted those (the github diff against current main showed it). Cherry-picking just the diagnosed fixes onto the current state preserved both your work and the recent additions.

Closing the PR — both fixes are now on main. Thanks for the thorough writeup; the verification table at the end (pre-patch / post-patch behavior with concrete output) made this trivial to triage.

@DeusData DeusData closed this May 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants